package com.aop.aspectj;

import java.util.Arrays;
import java.util.List;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

//声明为一个切面,需要把该类放入到IOC容器中,在声明一个切面。使用aspectj框架。
@Component
@Aspect
//指定切面的优先级,值越小优先级越高
//@Order 
public class LoggingAspect {
	
	//定义一个方法，用于声明切入点表达式，一般的，该方法中再不需要填入其他代码
	@Pointcut("execution(* com.aop.aspectj.*.*(..))")
	public void declareJoinPointExpression(){}
	
	//该方法是一个前置通知：在目标方法执行前执行
	//@Before("execution(public int com.aop.aspectj.ArithmeticCalculatorImpl.*(int, int))")
	//*匹配符分别代表所有的修饰符、返回值、包下的所有类和方法名称
	
	//@Before("execution(* com.aop.aspectj.*.*(..))")
	@Before("declareJoinPointExpression()")
	public void beforeMethod(JoinPoint joinPoint){
		//获取方法名
		String methodName=joinPoint.getSignature().getName();
		//获取方法的参数
		List<Object> args=Arrays.asList(joinPoint.getArgs());
		System.out.println("The method "+methodName+" begins with " + args);
	}
	
	//后置通知：在目标方法之后执行的通知（无论是否发生异常）
	//在后置通知中还不能访问目标方法执行的结果
	//不能访问到返回值
	//@After("execution(* com.aop.aspectj.*.*(..))")
	@After("declareJoinPointExpression()")
	public void afetrMethod(JoinPoint joinPoint){
		//获取方法名
		String methodName=joinPoint.getSignature().getName();
		System.out.println("The method "+methodName+" ends.");
	}
	
	//在方法正常结束后执行的代码,返回通知可以访问到访问值
	//@AfterReturning(value="execution(* com.aop.aspectj.*.*(..))",
	//		returning="result")
	@AfterReturning(value="declareJoinPointExpression()",
			returning="result")
	public void afterReturning(JoinPoint joinPoint,Object result){
		String methodName=joinPoint.getSignature().getName();
		System.out.println("The method "+methodName+" begins ends " + result);
	}
	
	//在方法出现异常时会执行的代码，可以访问到异常对象，可以指定在出现特定异常时再执行的通知
	/*@AfterThrowing(value="execution(* com.aop.aspectj.*.*(..))",
			throwing="ex")*/
	@AfterThrowing(value="declareJoinPointExpression()",
			throwing="ex")
	public void afterThrowing(JoinPoint joinPoint,Exception ex){
		String methodName=joinPoint.getSignature().getName();
		System.out.println("The method "+methodName+" occurs exception " + ex);
	}
	
	//环绕通知(功能最全，但不常用)，需要携带ProceedingJoinPoint类型的参数，
	//环绕通知类似于动态代理的全过程,ProceedingJoinPoint类型的参数可以决定是否执行目标方法
	//环绕通知必须有返回值，返回值即为目标方法的返回值
//	@Around("execution(* com.aop.aspectj.*.*(..)")
//	public Object aroundMethod(ProceedingJoinPoint pjp){
//		System.out.println("aroundMethod");
//		return 100;
//	}
	
}
